package org.vison.wonfu.framework.soa.discovery;

import com.ecwid.consul.v1.ConsulClient;
import com.ecwid.consul.v1.QueryParams;
import com.ecwid.consul.v1.Response;
import com.ecwid.consul.v1.agent.model.NewService;
import com.ecwid.consul.v1.catalog.CatalogServicesRequest;
import com.ecwid.consul.v1.health.HealthServicesRequest;
import com.ecwid.consul.v1.health.model.HealthService;
import org.springframework.stereotype.Component;
import org.vison.wonfu.framework.commons.Constants;
import org.vison.wonfu.framework.config.utils.MultiLevelConfigProvider;

import java.util.*;
import java.util.stream.Collectors;

@Component
public class ConsulServiceDiscovery extends AbstractServiceRegistryDiscovery implements ServiceRegistryDiscovery {

    private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(ConsulServiceDiscovery.class);

    private final MultiLevelConfigProvider governanceMultiLevelConfigProvider;

    private static final String REGISTRY_TAG = "java-app-node";
    private final ConsulClient consulClient;


    public ConsulServiceDiscovery(MultiLevelConfigProvider governanceMultiLevelConfigProvider,ConsulClient consulClient) {
        this.governanceMultiLevelConfigProvider = governanceMultiLevelConfigProvider;
        this.consulClient = consulClient;
    }

    @Override
    public void register(ServiceInstance service) {
        NewService newService = new NewService();
        newService.setName(service.getAppId());
        newService.setId(service.getServiceId());
        newService.setAddress(service.getHost());
        newService.setPort(service.getPort());
        List<String> tags = new ArrayList<>();
        tags.add(REGISTRY_TAG);
        newService.setTags(tags);
        NewService.Check check = new NewService.Check();
        String healthCheckEndpoint = governanceMultiLevelConfigProvider.getString(Constants.HEALTH_CHECK_ENDPOINT,"/actuator/health");
        String checkUrl = "http://" + service.getHost() + ":" + service.getPort() + healthCheckEndpoint;
        check.setHttp(checkUrl);
        check.setInterval(governanceMultiLevelConfigProvider.getString(Constants.HEALTH_CHECK_INTERVAL, "1s"));
        check.setTimeout(governanceMultiLevelConfigProvider.getString(Constants.HEALTH_CHECK_TIMEOUT, "5s"));
        newService.setCheck(check);
        try{
            consulClient.agentServiceRegister(newService);
        }catch(Exception e){
            logger.error("register service error", e);
            throw e;
        }
        logger.info("register service success service: {}",service);
    }

    @Override
    public void deregister(ServiceInstance service) {
        try{
            consulClient.agentServiceDeregister(service.getServiceId());
        }catch(Exception e){
            logger.error("deregister service error", e);
            throw e;
        }
        logger.info("deregister service success service: {}",service);
    }

    @Override
    public List<ServiceInstance> discover(String serviceId) {
        HealthServicesRequest request = HealthServicesRequest.newBuilder()
                .setPassing(true)
                .setQueryParams(QueryParams.DEFAULT)
                .build();
        Response<List<HealthService>> healthyServices = consulClient.getHealthServices(serviceId, request);
        return healthyServices.getValue().stream()
                .map(healthService -> new ServiceInstance(serviceId, healthService.getService().getAddress(),
                        healthService.getService().getPort()))
                .collect(Collectors.toList());
    }

    @Override
    public List<String> getServices() {
        CatalogServicesRequest servicesRequest = CatalogServicesRequest.newBuilder()
                .setQueryParams(QueryParams.DEFAULT) // 使用默认查询参数
                .build();
        // 调用 catalogClient 的 getServices 方法
        Response<Map<String, List<String>>> allServices = consulClient.getCatalogServices(servicesRequest);
        Map<String, List<String>> serviceNames = allServices.getValue();
        Set<String> serviceNamesSet = serviceNames.keySet();
        return new ArrayList<>(serviceNamesSet);
    }
}
